import json
import re
import cn2an
import itertools
#模块对外接口
def agg_module_interface(dimension_dict,dim_pos):
    ques=dimension_dict['question']
    agg_list=[]
    new_dict={}
    for sel in dimension_dict['sel']:
        agg_list.append(agg_key_word_match(ques,sel['id'],sel['name']))
    new_dict['question']=ques
    new_dict['agg']=agg_list
    limit_prediction=limit_predict(ques)
    new_dict['limit']=[] if limit_prediction==0 else [["LIMIT",str(limit_prediction)]]
    new_sel_list=operation_predict(ques,[sel['id'] for sel in dimension_dict['sel']],[sel['name'] for sel in dimension_dict['sel']])
    new_dict['agg'].extend(['SUM' for i in new_sel_list])
    tmp_sel_list=dimension_dict['sel'][:]
    new_dict['sel']=tmp_sel_list+new_sel_list
    new_dict['measure']=search_measure([sel['id'] for sel in dimension_dict['sel']])
    return new_dict
def agg_module_interface_v2(dimension_dict,dim_pos):
    ques=dimension_dict['question']
    # print(dimension_dict['sel'])
    dim_pos={item[0]:item[1] for item in dim_pos}
    
    sel_name_list=[sel['name'] for sel in dimension_dict['sel']]
    dim_pos=[dim_pos[sel_name] for sel_name in sel_name_list]
    sel_id_list=[sel['id'] for sel in dimension_dict['sel']]
    # agg_list=[]
    
    # for sel in dimension_dict['sel']:
    #     agg_list.append(agg_key_word_match(ques,sel['id'],sel['name']))
    agg_list=agg_key_word_match_v2(ques,sel_id_list,sel_name_list,dim_pos)
    mdx_list=operation_predict(ques,sel_id_list,sel_name_list,dim_pos)
    ans=[]
    for key,value in agg_list.items():
        new_dict={}
        new_dict['question']=key
        new_dict['agg']=value
        limit_prediction=limit_predict(ques)
        new_dict['limit']=[] if limit_prediction==0 else [["LIMIT",str(limit_prediction)]]
        new_dict['mdx']=mdx_list
        # new_dict['agg'].extend(['SUM' for i in new_sel_list])
        # tmp_sel_list=dimension_dict['sel'][:]
        new_dict['sel']=dimension_dict['sel'][:]
        new_dict['measure']=search_measure([sel['id'] for sel in dimension_dict['sel']])
        ans.append(new_dict)
    return ans
#构造通用查询字典
measure_dict={}
agg_mode_dict={}
with open('metaData/data_dict.json', 'r', encoding='utf-8') as json_file:
    data=json.load(json_file)
    # header=data[0]['header']+data[1]['header']
    header=data[1]['header']
    for item in header:
        if item['fieldType']=='MEASURE':
            measure_dict[item['id']]=True
        else:
            measure_dict[item['id']]=False
        if 'aggregationMode' in item.keys():
            agg_mode_dict[item['id']]=item['aggregationMode'] if item['aggregationMode']!='sum' else 'SUM'
#聚合函数识别
sum_key_pattern=re.compile(r'总和|之和|总量|总额|总的|全体|全部|合计')
avg_key_pattern=re.compile(r'平均值|均值|平均')
count_key_pattern=re.compile(r'计数|数量|个数|数目|有几家|多少家|有几部|多少个|有多少|有几个')

def agg_key_word_match(ques,id,name):
    if id in measure_dict.keys():
        is_measure=measure_dict[id]
        if is_measure:
            # default_agg='SUM'
            m=avg_key_pattern.search(ques)
            if m:
                return 'AVG'
            # m=count_key_pattern.search(ques)
            # if m:
            #     return 'distinct-count'
            m=sum_key_pattern.search(ques)
            if m:
                return 'SUM'
            if id in agg_mode_dict.keys():
                return agg_mode_dict[id]
            return ''
        else:
            if any(name_word in name for name_word in ['姓名','名字','名称']):
                m=count_key_pattern.search(ques)
                if m:
                    # print(m)
                    # print(m.span())
                    return 'distinct-count'
    return ''
sum_key_list=['总和','之和','总量','总额','总的','全体','全部','合计']
avg_key_list=['平均值ֵ','均值ֵ','平均']
count_key_list=['计数','数量','个数','数目','有几家','多少家','有几部','多少个','有多少','有几个']
list_key_list=['哪些','哪几个']
def agg_key_word_match_v2(ques,id_list,name_list,pos_list):
    assert len(id_list)==len(name_list) and len(id_list)==len(pos_list)
    #每个sel项构造一个字典(id,name,pos,is_measure,agg)
    all_info_tuples=[{'id':id_list[i],'name':name_list[i],'pos':pos_list[i],'is_measure':get_measure(id_list[i]),'agg':[]} for i in range(len(id_list))]
    all_info_tuples=sorted(all_info_tuples,key=lambda x:x['pos'][1])
    tmp_pos_list=[pos_list[i] for i in range(len(pos_list))]
    print(all_info_tuples)
    sum_key_index=sub_str_match(ques,sum_key_list,tmp_pos_list)
    avg_key_index=sub_str_match(ques,avg_key_list,tmp_pos_list)
    count_key_index=sub_str_match(ques,count_key_list,tmp_pos_list)
    list_key_index=sub_str_match(ques,list_key_list,tmp_pos_list)
    # print(sum_key_index)
    # print(avg_key_index)
    # print(count_key_index)
    # print(list_key_index)
    # for index in range(len(id_list)):
    #avg绑定
    for avg_index in avg_key_index:
        find_sel_index=-1#对应all_info_tuples里的第几个
        for (sel_index, sel_info) in enumerate(all_info_tuples):
            if sel_info['is_measure']:
                if avg_index[0]>sel_info['pos'][0]:#最后一个小于count_index的sel_index
                    find_sel_index=sel_index
        if find_sel_index!=-1:
            if 'avg' not in all_info_tuples[find_sel_index]['agg']:
                all_info_tuples[find_sel_index]['agg'].append(('avg',avg_index))
    #sum绑定
    for sum_index in sum_key_index:
        find_sel_index=-1#对应all_info_tuples里的第几个
        for (sel_index, sel_info) in enumerate(all_info_tuples):
            if sel_info['is_measure']:
                if sum_index[0]>sel_info['pos'][0]:#最后一个小于count_index的sel_index
                    find_sel_index=sel_index
        if find_sel_index!=-1:
            if 'sum' not in all_info_tuples[find_sel_index]['agg']:
                all_info_tuples[find_sel_index]['agg'].append(('sum',sum_index))
    #count绑定
    for count_index in count_key_index:
        find_sel_index=-1#对应all_info_tuples里的第几个
        for (sel_index, sel_info) in enumerate(all_info_tuples):
            if not sel_info['is_measure']:
                if count_index[0]>sel_info['pos'][0]:#最后一个小于count_index的sel_index
                    find_sel_index=sel_index
        if find_sel_index!=-1:
            if 'distinct-count' not in all_info_tuples[find_sel_index]['agg']:
                all_info_tuples[find_sel_index]['agg'].append(('distinct-count',count_index))
    #list绑定
    for list_index in list_key_index:
        find_sel_index=-1#对应all_info_tuples里的第几个
        for (sel_index, sel_info) in enumerate(all_info_tuples):
            if not sel_info['is_measure']:
                if list_index[0]>sel_info['pos'][0]:#最后一个小于count_index的sel_index
                    find_sel_index=sel_index
        if find_sel_index!=-1:
            if '' not in all_info_tuples[find_sel_index]['agg']:
                all_info_tuples[find_sel_index]['agg'].append(('',list_index))
    #还有一个维度后面跟着“和”、“，”、“、”的情况也视为list
    for (sel_index, sel_info) in enumerate(all_info_tuples):
        if not sel_info['is_measure'] and any([item==ques[sel_info['pos'][1]] for item in ['和',',','、']]):
            if '' not in all_info_tuples[sel_index]['agg']:
                all_info_tuples[sel_index]['agg'].append(('',(sel_info['pos'][1],sel_info['pos'][1]+1)))
    
    #把'list'转成''->现在不用了
    #没有聚合函数的给一个空聚合函数
    for (sel_index, sel_info) in enumerate(all_info_tuples):
        if len(sel_info['agg'])==0:
            all_info_tuples[sel_index]['agg'].append(('',(0,0)))
        # all_info_tuples[sel_index]['agg']=['' if item=='list' else item for item in sel_info['agg']]
    # if all(len(sel_info['agg'])<=1 for sel_info in all_info_tuples):
    #     for (sel_index, sel_info) in enumerate(all_info_tuples):
    #         if len(sel_info['agg'])==1:
    #             all_info_tuples[sel_index]['agg']=agg_mode_dict[sel_info['id']]
    #         else:
    #             if sel_info['id'] in agg_mode_dict.keys():
    #                 all_info_tuples[sel_index]['agg']=agg_mode_dict[sel_info['id']]

    #现在的agg里的格式是(agg,(start,end))
    #要改成(agg,(start,end),[other agg])
    for i in range(len(all_info_tuples)):
        new_agg=[(single_agg[0],[]) for single_agg in all_info_tuples[i]['agg']]
        for j in range(len(all_info_tuples[i]['agg'])):
            for k in range(len(all_info_tuples[i]['agg'])):
                if k!=j:
                    new_agg[j][1].append(all_info_tuples[i]['agg'][k][1])
        all_info_tuples[i]['agg']=new_agg
    
    print(all_info_tuples)
    origin_agg_list=[]
    id_agg_dict={all_info_tuples[i]['id']:all_info_tuples[i]['agg'] for i in range(len(all_info_tuples))}
    
    for sel_id in id_list:
        origin_agg_list.append(id_agg_dict[sel_id])
    combinations = itertools.product(*origin_agg_list)
    combinations=list(combinations)
    combinations=[list(combines) for combines in combinations]
    print(combinations)
    # print(all_info_tuples)
    # print(ans)
    ans_ques_list=[]
    ans_agg_list=[]
    for combines in combinations:
        tmp_word_pos_list=[]
        tmp_ans_agg_list=[item[0] for item in combines]
        for item in combines:
            tmp_word_pos_list.extend(item[1])
        ans_agg_list.append(tmp_ans_agg_list)
        ans_ques_list.append(get_outside_str(ques,tmp_word_pos_list))
    # return ['' for _ in id_list]
    ans={ans_ques_list[i]:ans_agg_list[i] for i in range(len(ans_ques_list))}
    print(ans)
    return ans
#从parent_str中识别key_word_list中的每个词，并且返回它们的起始位置和结束位置，保证它们不被包含在pos_list中的
def sub_str_match(parent_str,key_word_list,pos_list):
    ans=[]
    for word in key_word_list:
        
        position = parent_str.find(word)
        while position != -1:
            # print('出现位置：{}'.format(position))
            if not any([pos_list[i][0]<=position<pos_list[i][1] for i in range(len(pos_list))]):#防止类似于“个数”出现在“合同个数”里面的情况
                ans.append((position,position+len(word)))
            position = parent_str.find(word, position + 1)
    return ans
#输入id判断该列是否为measure
def get_measure(sel_id):
    if sel_id in measure_dict.keys():
        is_measure=measure_dict[sel_id]
        if is_measure:
            return True
    return False
#从origin_str中提取出不包含在range_list中的部分
def get_outside_str(origin_str,range_list):
    range_list=sorted(range_list,key=lambda x:x[0])
    ans=[]
    for (index, item) in enumerate(range_list):
        if index==0:
            ans.append(origin_str[:item[0]])
            if index==len(range_list)-1:
                ans.append(origin_str[item[1]:])
        elif index==len(range_list)-1:
            ans.append(origin_str[range_list[index-1][1]:item[0]])
            ans.append(origin_str[item[1]:])
        else:
            if range_list[index-1][1]>item[0]:
                return origin_str
            ans.append(origin_str[range_list[index-1][1]:item[0]])
    return ''.join(ans)
#limit识别
max_key_pattern=re.compile(r'最大值|极大值|极大')
min_key_pattern=re.compile(r'最小值|极小值|极小')
limit_1_key_pattern=re.compile(r'最大|最多|最好|最棒|最高|最厉害|最少|最小|最差|最低|排名最后')
limit_many_key_pattern=re.compile(r'(排名前(\d+)|排名后(\d+)|前(\d+)|后(\d+)|(\d+)个|(\d+)名|top(\d+)|第(\d+))(?!(个|年|月|日|季))')

def limit_predict(ques):
    limit=0
    ques=cn2an.transform(ques)
    m=limit_1_key_pattern.search(ques)
    if m:
        limit=1
    if limit==0:
        m=limit_many_key_pattern.search(ques)
        if m:
            for group in m.groups():
                if group:
                    limit=group
    return int(limit)
#measure字段补充
def search_measure(sel_id_list):
    measure_list=[]
    for sel_id in sel_id_list:
        if sel_id in measure_dict.keys():
            is_measure=measure_dict[sel_id]
            if is_measure:
                measure_list.append(sel_id)
    return measure_list
#指标操作识别
level_1_dict={
    '年累同期值':['年累同期值'],
    '年累同期增量':['年累同期增量'],'年累同期增长率':['年累同期增长率','年累同比','年累计同比'],
    '季累同期值':['季累同期值'],
    '季累同期增量':['季累同期增量'],'季累同期增长率':['季累同期增长率','季累同比','季累计同比'],
    '月累同期值':['月累同期值'],
    '月累同期增量':['月累同期增量'],'月累同期增长率':['月累同期增长率','月累同比','月累计同比'],
    '环比增长率':['环比增长率'],
    '前期增长':['前期增长','前期增量'],'前期值':['前期值','上期值'],
    '本期值':['本期值']
}
level_2_dict={
    '同期增长':['同期增量','同比增量','同比增长','同期增长'],
    '同期增长率':['同期增长率','同比增长率','同期比增长率'],
    '年累':['年累','年累计','年累计值'],'季累':['季累','季累计','季累计值'],
    '月累':['月累计','月累计值','月累'],
    '环比':['月环比','环比'],
}
level_3_dict={
    '同比':['同比','同期比'],
}
level_4_dict={
    '同期值':['同期值','同期'],
}
target_dict_list=[level_1_dict,level_2_dict,level_3_dict,level_4_dict]
include_dict={
    '同比':['本期值','同期值'],'同期增长':['本期值','同期值'],'同期增长率':['同期增长','本期值','同期值'],
    '年累同期增量':['年累','年累同期值'],'年累同期增长率':['年累同期增量','年累','年累同期值'],
    '季累同期增量':['季累','季累同期值'],'季累同期增长率':['季累同期增量','季累','季累同期值'],
    '月累同期增量':['月累','月累同期值'],'月累同期增长率':['月累同期增量','月累','月累同期值'],
    '前期增长':['前期值','本期值'],'环比':['前期值','本期值'],
    '环比增长率':['前期值','前期增长'],
}

target_dict={'同期值':['同期值','同期'],'同期增长':['同期增量','同比增量','同比增长','同期增长'],
                 '同比':['同比','同期比'],'同期增长率':['同期增长率','同比增长率','同期比增长率'],
                 '年累':['年累','年累计','年累计值'],'年累同期值':['年累同期值'],
                 '年累同期增量':['年累同期增量'],'年累同期增长率':['年累同期增长率','年累同比','年累计同比'],
                 '季累':['季累','季累计','季累计值'],'季累同期值':['季累同期值'],
                 '季累同期增量':['季累同期增量'],'季累同期增长率':['季累同期增长率','季累同比','季累计同比'],
                 '月累':['月累计','月累计值','月累'],'月累同期值':['月累同期值'],
                 '月累同期增量':['月累同期增量'],'月累同期增长率':['月累同期增长率','月累同比','月累计同比'],
                 '环比':['月环比','环比'],'环比增长率':['环比增长率'],
                 '前期增长':['前期增长','前期增量'],'前期值':['前期值','上期值']}
synonyms2mdx={}
for key,value in target_dict.items():
    for word in value:
        synonyms2mdx[word]=key
def combine_func(measure_name,measure_id,time_id,op_name,unit="万元"):
    CorrespondingPeriodName=measure_name+op_name
    if op_name=='本期值':
        mdx_temp=op_name+'('+measure_id+')'
    else:
        mdx_temp=op_name+'('+measure_id+' , '+time_id+')'
    return {"mdx":mdx_temp,"dataFormat": unit, "name": CorrespondingPeriodName,
                   "id": CorrespondingPeriodName, "type": "MEASURE"}
def operation_predict(ques, sel_id_list, sel_name_list):
    # 将类型为measure的id识别出来
    opt_index=-1
    time_index=-1
    for (index, item) in enumerate(sel_id_list):
        if item in measure_dict.keys():
            if measure_dict[item]:
                opt_index = index
                opt = item
    for (index, item) in enumerate(sel_name_list):
        if any(timelv in item for timelv in ['年','月','日']):
            time_index=index
    if opt_index==-1 or time_index==-1:
        return []

    measure_name=sel_name_list[opt_index]
    measure_id=sel_id_list[opt_index]
    time_id=sel_id_list[time_index]
    metric_list=set()
    for target_dict in target_dict_list:
        for key,value in target_dict.items():
            for term in value:
                if term in ques:
                    metric_list.add(key)
                    if key in include_dict.keys():
                        metric_list.update(include_dict[key])
                    ques=re.sub(term,'',ques)
                    break
    ans=[]
    for op_metric in metric_list:
        if '率' in op_metric or '比' in op_metric:
            ans.append(combine_func(measure_name,measure_id,time_id,op_metric,"INSIGHT_AUTO_PERCENT"))
        else:
            ans.append(combine_func(measure_name,measure_id,time_id,op_metric,"万元"))
    return ans
#重构扩展指标操作，使其能够处理并列句；不再含有dataformat和type字段；并且将mdx作为一个单独的列表返回
def operation_predict_v2(ques,sel_id_list,sel_name_list,pos_list):
    assert len(id_list)==len(name_list) and len(id_list)==len(pos_list)
    mdx_list=[]
    ques_words = jieba.cut(ques)
    ques_words=list(ques_words)
    ques_words_pos=[0]
    pre_pos=0
    for i in range(1,len(ques_words)):
        ques_words_pos.append(ques_words_pos[-1]+len(ques_words[i]))

    #每个sel项构造一个字典(id,name,pos,is_measure,agg)
    all_info_tuples=[{'id':id_list[i],'name':name_list[i],'pos':pos_list[i],'is_measure':get_measure(id_list[i]),'mdx':[]} for i in range(len(id_list))]
    all_info_tuples=sorted(all_info_tuples,key=lambda x:x['pos'][1])
    for index,ques_word in enumerate(ques_words):
        if ques_word in synonyms2mdx.keys():
            word2mdx=synonyms2mdx[ques_word]
            tmp_pos=ques_words_pos[index]
            find_sel_index=-1#对应all_info_tuples里的第几个
            for (sel_index, sel_info) in enumerate(all_info_tuples):
                if not sel_info['is_measure']:
                    if tmp_pos>sel_info['pos'][0]:#最后一个小于count_index的sel_index
                        find_sel_index=sel_index
            if find_sel_index!=-1:
                all_info_tuples[find_sel_index]['mdx'].append(('',list_index))
    for info_term in all_info_tuples:
        for mdx_term in info_term['mdx']:
            mdx_list.append((mdx_term,info_term['name'],info_term['id']))#如果后期还需要对单个mdx的信息进行修改就在此处修改
    return mdx_list

if __name__ == '__main__':
    test_dict={
    "question": "今年9月合同金额的同期比",
    "sel": [
        {
            "member_amount": 1,
            "name": "月",
            "timeLevel": "month",
            "id": "AUGMENTED_DATASET_LEVEL.I8a8ae5ca0178549554951b9501785cefe3f00058.MT_DIMENSION_FIELD.02de0a83c07e6c06b5f6dc8d09f9fce7-C_DATE_Month-LEVEL-1648634671682",
            "type": "STRING"
        },
        {
            "member_amount": 0,
            "name": "合同金额",
            "timeLevel": "",
            "id": "AUGMENTED_DATASET_MEASURE.I8a8ae5ca0178549554951b9501785cefe3f00058.MT_METRICS.I8a8ae5ca0178549554951b9501785d983aaa005e",
            "type": "DOUBLE"
        },
    ],
    }
    print(agg_module_interface(test_dict))